/*     */ package com.zimbra.cs.service.authenticator;
/*     */ 
/*     */ import com.zimbra.common.account.Key.AccountBy;
/*     */ import com.zimbra.common.account.Key.DomainBy;
/*     */ import com.zimbra.common.service.ServiceException;
/*     */ import com.zimbra.common.util.HttpUtil;
/*     */ import com.zimbra.common.util.Log;
/*     */ import com.zimbra.common.util.ZimbraLog;
/*     */ import com.zimbra.cs.account.Account;
/*     */ import com.zimbra.cs.account.Config;
/*     */ import com.zimbra.cs.account.Entry;
/*     */ import com.zimbra.cs.account.NamedEntry;
/*     */ import com.zimbra.cs.account.Provisioning;
/*     */ import com.zimbra.cs.account.SearchAccountsOptions;
/*     */ import com.zimbra.cs.ldap.ZLdapFilterFactory.FilterId;
/*     */ import java.security.cert.X509Certificate;
/*     */ import java.util.ArrayList;
/*     */ import java.util.List;
/*     */ import java.util.regex.Matcher;
/*     */ import java.util.regex.Pattern;
/*     */ import javax.servlet.http.HttpServletRequest;
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ public class ClientCertPrincipalMap
/*     */ {
/*     */   static final String LOG_PREFIX = "certauth - ";
/*     */   private static final String RULE_DELIMITER = ",";
/*     */   private static final char LDAP_FILTER_LEADING_CHAR = '(';
/*     */   private static final String MAP_DELIMITER = "=";
/*     */   private List<Rule> rules;
/*     */   
/*     */   static abstract class CertField
/*     */   {
/*     */     abstract String getName();
/*     */   }
/*     */   
/*     */   static class KnownCertField
/*     */     extends ClientCertPrincipalMap.CertField
/*     */   {
/*     */     private Field field;
/*     */     
/*     */     static enum Field
/*     */     {
/*  54 */       SUBJECT_DN, 
/*  55 */       SUBJECTALTNAME_OTHERNAME_UPN, 
/*  56 */       SUBJECTALTNAME_RFC822NAME;
/*     */       
/*     */       private ClientCertPrincipalMap.KnownCertField knownCertField;
/*     */       
/*  60 */       private Field() { this.knownCertField = new ClientCertPrincipalMap.KnownCertField(this, null); }
/*     */       
/*     */       private ClientCertPrincipalMap.KnownCertField getKnownCertField()
/*     */       {
/*  64 */         return this.knownCertField;
/*     */       }
/*     */       
/*     */       private static String names() {
/*  68 */         StringBuilder str = new StringBuilder();
/*  69 */         int i = 0;
/*  70 */         for (Field type : values()) {
/*  71 */           if (i++ > 0) str.append('|');
/*  72 */           str.append(type.name());
/*     */         }
/*  74 */         return str.toString();
/*     */       }
/*     */     }
/*     */     
/*     */ 
/*     */     private KnownCertField(Field field)
/*     */     {
/*  81 */       this.field = field;
/*     */     }
/*     */     
/*     */     private static KnownCertField parse(String fieldStr) {
/*     */       try {
/*  86 */         Field parsedField = Field.valueOf(fieldStr);
/*  87 */         return parsedField.getKnownCertField();
/*     */       } catch (IllegalArgumentException e) {}
/*  89 */       return null;
/*     */     }
/*     */     
/*     */     static String names()
/*     */     {
/*  94 */       return Field.access$200();
/*     */     }
/*     */     
/*     */     Field getField() {
/*  98 */       return this.field;
/*     */     }
/*     */     
/*     */     String getName()
/*     */     {
/* 103 */       return this.field.name();
/*     */     }
/*     */   }
/*     */   
/*     */   static class SubjectCertField
/*     */     extends ClientCertPrincipalMap.CertField
/*     */   {
/*     */     private static final String PREFIX = "SUBJECT_";
/* 111 */     private static final int PREFIX_LEN = "SUBJECT_".length();
/*     */     
/*     */ 
/* 114 */     private static final SubjectCertField EMAILADDRESS = new SubjectCertField("EMAILADDRESS");
/*     */     String rdnAttrType;
/*     */     
/*     */     private SubjectCertField(String rdnType)
/*     */     {
/* 119 */       this.rdnAttrType = rdnType;
/*     */     }
/*     */     
/*     */     static SubjectCertField parse(String fieldStr) {
/* 123 */       if ((fieldStr.startsWith("SUBJECT_")) && (fieldStr.length() > PREFIX_LEN)) {
/* 124 */         String rdnType = fieldStr.substring(PREFIX_LEN);
/* 125 */         return new SubjectCertField(rdnType);
/*     */       }
/* 127 */       return null;
/*     */     }
/*     */     
/*     */     static String names() {
/* 131 */       return "SUBJECT_{an RDN attr, e.g. CN}";
/*     */     }
/*     */     
/*     */     String getRDNAttrType() {
/* 135 */       return this.rdnAttrType;
/*     */     }
/*     */     
/*     */     String getName()
/*     */     {
/* 140 */       return "SUBJECT_" + this.rdnAttrType;
/*     */     }
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   static enum ZimbraKey
/*     */   {
/* 152 */     name, 
/* 153 */     zimbraId, 
/* 154 */     zimbraForeignPrincipal;
/*     */     
/*     */     private ZimbraKey() {}
/*     */   }
/*     */   
/*     */   static abstract class Rule { abstract String getName();
/*     */     
/*     */     abstract SSOAuthenticator.ZimbraPrincipal apply(X509Certificate paramX509Certificate) throws ServiceException; }
/*     */   
/* 163 */   static class LdapFilterRule extends ClientCertPrincipalMap.Rule { private static Pattern pattern = Pattern.compile("\\%\\{([^\\}]*)\\}");
/*     */     private String filter;
/*     */     
/*     */     private LdapFilterRule(String filter)
/*     */     {
/* 168 */       this.filter = filter;
/*     */     }
/*     */     
/*     */     String getFilter() {
/* 172 */       return this.filter;
/*     */     }
/*     */     
/*     */     String getName()
/*     */     {
/* 177 */       return this.filter;
/*     */     }
/*     */     
/*     */     SSOAuthenticator.ZimbraPrincipal apply(X509Certificate cert) throws ServiceException
/*     */     {
/* 182 */       String filter = expandFilter(cert);
/* 183 */       ZimbraLog.account.debug("certauth - search account by expanded filter(prepended with account objectClass filter): " + filter);
/*     */       
/*     */ 
/* 186 */       SearchAccountsOptions searchOpts = new SearchAccountsOptions();
/* 187 */       searchOpts.setMaxResults(1);
/* 188 */       searchOpts.setFilterString(ZLdapFilterFactory.FilterId.ACCOUNT_BY_SSL_CLENT_CERT_PRINCIPAL_MAP, filter);
/*     */       
/*     */ 
/*     */ 
/* 192 */       List<NamedEntry> entries = Provisioning.getInstance().searchDirectory(searchOpts);
/*     */       
/* 194 */       if (entries.size() == 1) {
/* 195 */         Account acct = (Account)entries.get(0);
/* 196 */         return new SSOAuthenticator.ZimbraPrincipal(filter, acct);
/*     */       }
/* 198 */       return null;
/*     */     }
/*     */     
/*     */     private String expandFilter(X509Certificate cert) throws ServiceException
/*     */     {
/* 203 */       CertUtil certUtil = new CertUtil(cert);
/*     */       
/* 205 */       Matcher matcher = pattern.matcher(getFilter());
/* 206 */       StringBuffer sb = new StringBuffer();
/* 207 */       while (matcher.find()) {
/* 208 */         String rawCertField = matcher.group(1);
/* 209 */         ClientCertPrincipalMap.CertField certField = ClientCertPrincipalMap.parseCertField(rawCertField);
/* 210 */         String certFieldValue = certUtil.getCertField(certField);
/*     */         
/* 212 */         matcher.appendReplacement(sb, certFieldValue);
/*     */       }
/* 214 */       matcher.appendTail(sb);
/* 215 */       return sb.toString();
/*     */     }
/*     */   }
/*     */   
/*     */   static class FieldMapRule extends ClientCertPrincipalMap.Rule {
/*     */     private ClientCertPrincipalMap.CertField certField;
/*     */     private ClientCertPrincipalMap.ZimbraKey zimbraKey;
/*     */     
/*     */     private FieldMapRule(ClientCertPrincipalMap.CertField certField, ClientCertPrincipalMap.ZimbraKey zimbraKey) {
/* 224 */       this.certField = certField;
/* 225 */       this.zimbraKey = zimbraKey;
/*     */     }
/*     */     
/*     */     ClientCertPrincipalMap.CertField getCertField() {
/* 229 */       return this.certField;
/*     */     }
/*     */     
/*     */     ClientCertPrincipalMap.ZimbraKey getZimbraKey() {
/* 233 */       return this.zimbraKey;
/*     */     }
/*     */     
/*     */     String getName()
/*     */     {
/* 238 */       return this.certField.getName() + "=" + this.zimbraKey.name();
/*     */     }
/*     */     
/*     */     SSOAuthenticator.ZimbraPrincipal apply(X509Certificate cert) throws ServiceException
/*     */     {
/* 243 */       CertUtil certUtil = new CertUtil(cert);
/*     */       
/* 245 */       String certFieldValue = certUtil.getCertField(getCertField());
/* 246 */       if (certFieldValue != null) {
/* 247 */         Account acct = getZimbraAccount(getZimbraKey(), getCertField(), certFieldValue);
/* 248 */         if (acct != null) {
/* 249 */           return new SSOAuthenticator.ZimbraPrincipal(certFieldValue, acct);
/*     */         }
/*     */       }
/*     */       
/* 253 */       return null;
/*     */     }
/*     */     
/*     */     private Account getZimbraAccount(ClientCertPrincipalMap.ZimbraKey zimbraKey, ClientCertPrincipalMap.CertField certField, String certFieldValue) {
/* 257 */       ZimbraLog.account.debug("certauth - get account by " + zimbraKey.name() + ", " + certField.getName() + "=" + certFieldValue);
/*     */       
/*     */ 
/* 260 */       Provisioning prov = Provisioning.getInstance();
/* 261 */       Account acct = null;
/*     */       try
/*     */       {
/* 264 */         switch (ClientCertPrincipalMap.1.$SwitchMap$com$zimbra$cs$service$authenticator$ClientCertPrincipalMap$ZimbraKey[zimbraKey.ordinal()]) {
/*     */         case 1: 
/* 266 */           acct = prov.get(Key.AccountBy.name, certFieldValue);
/* 267 */           break;
/*     */         case 2: 
/* 269 */           acct = prov.get(Key.AccountBy.id, certFieldValue);
/* 270 */           break;
/*     */         case 3: 
/* 272 */           String foreignPrincipal = String.format("cert %s:%s", new Object[] { certField.getName(), certFieldValue });
/*     */           
/* 274 */           acct = prov.get(Key.AccountBy.foreignPrincipal, foreignPrincipal);
/*     */         }
/*     */       }
/*     */       catch (ServiceException e) {
/* 278 */         ZimbraLog.account.debug("certauth - no matching account by " + zimbraKey.name() + ", " + certField.getName() + "=" + certFieldValue, e);
/*     */       }
/*     */       
/* 281 */       return acct;
/*     */     }
/*     */   }
/*     */   
/*     */ 
/*     */   ClientCertPrincipalMap(HttpServletRequest req)
/*     */     throws ServiceException
/*     */   {
/* 289 */     String rawRules = getMappingConfig(req);
/* 290 */     this.rules = parse(rawRules);
/*     */   }
/*     */   
/*     */   List<Rule> getRules() {
/* 294 */     return this.rules;
/*     */   }
/*     */   
/*     */   private String getMappingConfig(HttpServletRequest req) throws ServiceException {
/* 298 */     Provisioning prov = Provisioning.getInstance();
/*     */     
/* 300 */     String virtualHostName = HttpUtil.getVirtualHost(req);
/* 301 */     Entry entry = prov.get(Key.DomainBy.virtualHostname, virtualHostName);
/* 302 */     if (entry == null) {
/* 303 */       entry = prov.getConfig();
/*     */     }
/*     */     
/* 306 */     return entry.getAttr("zimbraMailSSLClientCertPrincipalMap");
/*     */   }
/*     */   
/*     */   private List<Rule> parse(String rawRules) throws ServiceException {
/* 310 */     List<Rule> parsedRules = new ArrayList();
/*     */     
/* 312 */     if (rawRules == null)
/*     */     {
/* 314 */       Rule rule = new FieldMapRule(SubjectCertField.EMAILADDRESS, ZimbraKey.name, null);
/*     */       
/* 316 */       ZimbraLog.account.warn("certauth - No zimbraMailSSLClientCertPrincipalMap configured, default to " + rule.getName());
/*     */       
/*     */ 
/* 319 */       parsedRules.add(rule);
/*     */     } else {
/* 321 */       boolean ldapFilterRuleEnabled = Provisioning.getInstance().getConfig().isMailSSLClientCertPrincipalMapLdapFilterEnabled();
/*     */       
/*     */ 
/* 324 */       String[] rules = rawRules.split(",");
/*     */       
/* 326 */       for (String rawRule : rules) {
/* 327 */         Rule rule = null;
/* 328 */         if ('(' == rawRule.charAt(0)) {
/* 329 */           if (!ldapFilterRuleEnabled) {
/* 330 */             throw ServiceException.FAILURE("LDAP filter is not allowed: " + rawRule, null);
/*     */           }
/* 332 */           rule = new LdapFilterRule(rawRule, null);
/*     */         } else {
/* 334 */           rule = parseFieldMapRule(rawRule);
/*     */         }
/* 336 */         parsedRules.add(rule);
/*     */       }
/*     */     }
/*     */     
/* 340 */     return parsedRules;
/*     */   }
/*     */   
/*     */   private Rule parseFieldMapRule(String rawRule) throws ServiceException
/*     */   {
/* 345 */     String[] parts = rawRule.split("=");
/* 346 */     if (parts.length != 2) {
/* 347 */       throw ServiceException.FAILURE("Invalid config:" + rawRule + " in " + "zimbraMailSSLClientCertPrincipalMap", null);
/*     */     }
/*     */     
/*     */     try
/*     */     {
/* 352 */       String certPart = parts[0].trim();
/* 353 */       String zimbraPart = parts[1].trim();
/*     */       
/* 355 */       CertField certField = parseCertField(certPart);
/* 356 */       ZimbraKey zimbraKey = ZimbraKey.valueOf(zimbraPart);
/*     */       
/* 358 */       return new FieldMapRule(certField, zimbraKey, null);
/*     */     }
/*     */     catch (ServiceException e) {
/* 361 */       throw ServiceException.FAILURE("Invalid config:" + rawRule + " in " + "zimbraMailSSLClientCertPrincipalMap", e);
/*     */     }
/*     */   }
/*     */   
/*     */   static CertField parseCertField(String rawCertField)
/*     */     throws ServiceException
/*     */   {
/* 368 */     CertField certField = KnownCertField.parse(rawCertField);
/* 369 */     if (certField == null)
/*     */     {
/* 371 */       certField = SubjectCertField.parse(rawCertField);
/*     */     }
/*     */     
/* 374 */     if (certField == null) {
/* 375 */       throw ServiceException.FAILURE("Invalid cert field:" + rawCertField, null);
/*     */     }
/* 377 */     return certField;
/*     */   }
/*     */ }


/* Location:              /home/mint/zimbrastore.jar!/com/zimbra/cs/service/authenticator/ClientCertPrincipalMap.class
 * Java compiler version: 7 (51.0)
 * JD-Core Version:       0.7.1
 */